/*
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/

#include <ia32/asm.h>

.text

/* int atomic_add(int *val, int incr) */
ENTRY(atomic_add)
	movl	4(%esp),%edx
	movl	8(%esp),%eax
	lock
	xaddl	%eax,(%edx)
	ret

/* int atomic_and(int *val, int incr) */
ENTRY(atomic_and)
	movl	4(%esp),%edx

_atomic_and1:
	movl	8(%esp),%ecx
	movl	(%edx),%eax
	andl	%eax,%ecx

	lock
	cmpxchgl	%ecx,(%edx)

	jnz		_atomic_and1

	ret

/* int atomic_or(int *val, int incr) */
ENTRY(atomic_or)
	movl	4(%esp),%edx

_atomic_or1:
	movl	8(%esp),%ecx
	movl	(%edx),%eax
	orl		%eax,%ecx

	lock
	cmpxchgl	%ecx,(%edx)

	jnz		_atomic_or1

	ret

/* int atomic_set(int *val, int set_to) */
ENTRY(atomic_set)
	movl	4(%esp),%edx
	movl	8(%esp),%eax
	xchg	%eax,(%edx)
	ret

/* int test_and_set(int *val, int set_to, int test_val) */
ENTRY(test_and_set)
	movl	4(%esp),%edx
	movl	8(%esp),%ecx
	movl	12(%esp),%eax

	lock
	cmpxchgl	%ecx,(%edx)

	ret
#if 0
/* saves the conversion factor needed for system_time */
cv_factor:
	.word 0

ENTRY(setup_system_time)
	movl	4(%esp),%eax
	movl	%eax,cv_factor
	ret

/* long long system_time(); */
ENTRY(system_time)
	/* load 64-bit factor into %eax (low), %edx (high) */
	rdtsc		/* time in %edx,%eax */

	pushl	%ebx
	pushl	%ecx
	movl	cv_factor, %ebx
	movl	%edx, %ecx	/* save high half */
	mull	%ebx 		/* truncate %eax, but keep %edx */
	movl	%ecx, %eax
	movl	%edx, %ecx	/* save high half of low */
	mull	%ebx /*, %eax*/
	/* now compute  [%edx, %eax] + [%ecx], propagating carry */
	subl	%ebx, %ebx	/* need zero to propagate carry */
	addl	%ecx, %eax
	adc		%ebx, %edx
	popl	%ecx
	popl	%ebx
	ret

/* void i386_switch_stack_and_call(addr_t stack, void (*func)(void *), void *arg); */
ENTRY(i386_switch_stack_and_call)
	movl	4(%esp),%eax	// new stack
	movl	8(%esp),%ecx	// func
	movl	12(%esp),%edx	// args

	movl	%eax,%esp		// switch the stack
	pushl	%edx			// push the argument
	call	*%ecx			// call the target function
_loop:
	jmp		_loop

#endif
